{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Multiclass segmentation with the Lovász-Softmax\n",
    "## Tensorflow version, see PyTorch version for more details & use in training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from __future__ import division, print_function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import lovasz_losses_tf as L"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# add parent path to pythonpath to import demo_utils\n",
    "import sys\n",
    "sys.path.append('../demo_helpers')\n",
    "from demo_utils import pil_grid, dummy_triangles, printoptions\n",
    "from demo_utils_tf import define_scope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# add pytorch folder to path for comparison\n",
    "sys.path.append('../pytorch')\n",
    "import lovasz_losses as L_pytorch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Batch of 2 random images with classes [0, 1, 2] and void (255)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<PIL.Image.Image image mode=RGB size=402x202 at 0x7F9E5DC36FD0>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.random.seed(18)\n",
    "IGNORE = 255\n",
    "C = 3\n",
    "B = 2\n",
    "H = 200\n",
    "labels_ = [dummy_triangles(H, [0, 255, 1, 2]) for b in range(B)]\n",
    "labels = np.stack(map(np.array, labels_)).astype(np.uint8)\n",
    "pil_grid(labels_, 5, margin=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Features"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "np.random.seed(57)\n",
    "B, H, W = labels.shape\n",
    "labels_ = labels.copy()\n",
    "labels_[labels_ == 255] = np.random.randint(C, size=labels_.shape)[labels_ == 255] # random feats for void\n",
    "labels_1hot = np.zeros((B, C, H, W))\n",
    "for (b, h, w), c in np.ndenumerate(labels_):\n",
    "    labels_1hot[b, c, h, w] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "feats = labels_1hot.copy()\n",
    "feats += np.random.normal(0, 2, size=feats.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### PyTorch reference"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch.autograd import Variable\n",
    "import torch.nn.functional as F\n",
    "from torch.optim import Adam\n",
    "from torch import nn\n",
    "import lovasz_losses as L_pytorch\n",
    "\n",
    "class ModelPytorch(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(ModelPytorch, self).__init__()\n",
    "        self.conv = nn.Conv2d(C, C, 3, padding=1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        return x + self.conv(x)\n",
    "\n",
    "m_torch = ModelPytorch().cuda()\n",
    "out = m_torch(Variable(torch.from_numpy(feats.astype(np.float32)).cuda()))\n",
    "out = F.softmax(out)\n",
    "loss_torch = L_pytorch.lovasz_softmax(out, torch.from_numpy(labels).cuda(),\n",
    "                                      only_present=True, ignore=IGNORE, per_image=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.3355 0.2288 0.7424 0.0829 0.8521 0.0757 0.0143 0.8725 0.5713 0.4565]\n",
      " [0.4779 0.8647 0.5776 0.0321 0.4146 0.0143 0.6375 0.8737 0.6001 0.8027]\n",
      " [0.9806 0.0528 0.0015 0.671  0.0095 0.9874 0.7075 0.0039 0.2106 0.987 ]\n",
      " [0.0802 0.9387 0.7126 0.5766 0.0362 0.9507 0.0004 0.0969 0.9088 0.9337]\n",
      " [0.6104 0.0255 0.0414 0.2045 0.9676 0.8938 0.6495 0.1372 0.0686 0.1333]\n",
      " [0.0665 0.0721 0.9964 0.9284 0.7498 0.382  0.0924 0.1466 0.4221 0.9914]\n",
      " [0.2396 0.1232 0.2587 0.0093 0.017  0.9666 0.0502 0.0859 0.7002 0.1966]\n",
      " [0.6159 0.6652 0.0074 0.4776 0.8972 0.6777 0.2861 0.4919 0.7389 0.354 ]\n",
      " [0.8986 0.9128 0.0385 0.9902 0.549  0.8943 0.2148 0.2527 0.874  0.3742]\n",
      " [0.0492 0.2115 0.0074 0.0697 0.7794 0.0197 0.0046 0.0268 0.0148 0.2851]]\n"
     ]
    }
   ],
   "source": [
    "with printoptions(precision=4, suppress=True):\n",
    "    print(out[0, 0, :10, :10].data.cpu().numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7949457"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "loss_torch.data.cpu().numpy()[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### small gradient check"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "loss_torch.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.04259117,  0.02204291,  0.02054827], dtype=float32)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_torch.conv.bias.grad.data.cpu().numpy()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tensorflow model definition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Model:\n",
    "    '''\n",
    "    Simple linear model\n",
    "    '''\n",
    "    \n",
    "    def __init__(self, feats):\n",
    "        self.feats = feats\n",
    "        self.scores\n",
    "        self.predict\n",
    "\n",
    "    @define_scope\n",
    "    def scores(self):\n",
    "        x = self.feats\n",
    "        # replicate pytorch initialization\n",
    "        init_weight = m_torch.conv.weight.data.cpu().numpy().transpose((2, 3, 1, 0))\n",
    "        init_bias = m_torch.conv.bias.data.cpu().numpy()\n",
    "        out = tf.nn.conv2d(x, tf.Variable(init_weight), strides=[1, 1, 1, 1], padding=\"SAME\")\n",
    "        out = tf.nn.bias_add(out, tf.Variable(init_bias))\n",
    "        return x + out\n",
    "    \n",
    "    @define_scope\n",
    "    def probas(self):\n",
    "        return tf.nn.softmax(self.scores, 3)\n",
    "    \n",
    "    @define_scope\n",
    "    def predict(self):\n",
    "        return tf.argmax(self.scores, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "sess = tf.InteractiveSession()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "labels_tf = tf.placeholder(np.int64, shape=(None, H, W), name='labels')\n",
    "feats_tf = tf.placeholder(np.float32, shape=(None, H, W, C), name='features')\n",
    "\n",
    "feed_dict = {labels_tf: labels, \n",
    "             feats_tf: feats.transpose(0, 2, 3, 1)}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "m = Model(feats_tf)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "sess.run(tf.global_variables_initializer())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "loss = L.lovasz_softmax(m.probas, labels_tf, only_present=True,\n",
    "                        ignore=IGNORE, per_image=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 200, 200, 3)"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m.probas.eval(feed_dict).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.3355 0.2288 0.7424 0.0829 0.8521 0.0757 0.0143 0.8725 0.5713 0.4565]\n",
      " [0.4779 0.8647 0.5776 0.0321 0.4146 0.0143 0.6375 0.8737 0.6001 0.8027]\n",
      " [0.9806 0.0528 0.0015 0.671  0.0095 0.9874 0.7075 0.0039 0.2106 0.987 ]\n",
      " [0.0802 0.9387 0.7126 0.5766 0.0362 0.9507 0.0004 0.0969 0.9088 0.9337]\n",
      " [0.6104 0.0255 0.0414 0.2045 0.9676 0.8938 0.6495 0.1372 0.0686 0.1333]\n",
      " [0.0665 0.0721 0.9964 0.9284 0.7498 0.382  0.0924 0.1466 0.4221 0.9914]\n",
      " [0.2396 0.1232 0.2587 0.0093 0.017  0.9666 0.0502 0.0859 0.7002 0.1966]\n",
      " [0.6159 0.6652 0.0074 0.4776 0.8972 0.6777 0.2861 0.4919 0.7389 0.354 ]\n",
      " [0.8986 0.9128 0.0385 0.9902 0.549  0.8943 0.2148 0.2527 0.874  0.3742]\n",
      " [0.0492 0.2115 0.0074 0.0697 0.7794 0.0197 0.0046 0.0268 0.0148 0.2851]]\n"
     ]
    }
   ],
   "source": [
    "with printoptions(precision=4, suppress=True):\n",
    "    print(m.probas.eval(feed_dict)[0, :10, :10, 0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7949457"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "loss.eval(feed_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Gradient w.r.t. bias"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<tf.Variable 'scores/Variable:0' shape=(3, 3, 3, 3) dtype=float32_ref>,\n",
       " <tf.Variable 'scores/Variable_1:0' shape=(3,) dtype=float32_ref>]"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.trainable_variables()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.04259118,  0.02204292,  0.02054827], dtype=float32)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.gradients(loss, tf.trainable_variables()[1])[0].eval(feed_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda env:neural5]",
   "language": "python",
   "name": "conda-env-neural5-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.14"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
